package com.coding.mybatis;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName DefaultExecutor
 * @Author ykx
 * @Date 2023/12/31 17:09
 * @Version 1.0
 */
public class DefaultExecutor implements Executor {

    private Connection connection = null;

    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception {
        connection = configuration.getDataSource().getConnection();
        BoundSql boundSql = getBoundSql(mappedStatement);
        String sql = boundSql.getSql();

        Class<?> parameterType = mappedStatement.getParameterType();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

        int i = 0;
        for (ParameterMapping parameterMapping : parameterMappings) {
            String name = parameterMapping.getName();
            Field field = parameterType.getDeclaredField(name);
            field.setAccessible(Boolean.TRUE);
            Object o = field.get(params[0]);
            preparedStatement.setObject(++i, o);
        }

        ResultSet resultSet = preparedStatement.executeQuery();
        Class<?> resultType = mappedStatement.getResultType();
        List<E> results = new ArrayList<>();

        while (resultSet.next()) {
            ResultSetMetaData metaData = resultSet.getMetaData();
            E e = (E) resultType.getDeclaredConstructor().newInstance();

            int columnCount = metaData.getColumnCount();
            for (int j = 1; j <= columnCount; j++) {
                String columnName = metaData.getColumnName(j);
                Object value = resultSet.getObject(columnName);
                Field declaredField = e.getClass().getDeclaredField(columnName);
                declaredField.setAccessible(Boolean.TRUE);
                declaredField.set(e, value);
            }
            results.add(e);
        }

        return results;
    }

    @Override
    public void close() throws Exception {
        connection.close();
    }

    private BoundSql getBoundSql(MappedStatement mappedStatement) {
        ParameterMappingTokenHandler parameterMappingTokenHandler = new
                ParameterMappingTokenHandler(mappedStatement);
        GenericTokenParser genericTokenParser = new
                GenericTokenParser("#{", "}", parameterMappingTokenHandler);

        // 找到SQL字符串中的#{}标记，替换为?占位符
        String parsedSql = genericTokenParser.parse(mappedStatement.getSql());
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();

        return new BoundSql(parsedSql, parameterMappings);

    }

}
